/**
 * 
 */
package org.jenkon.commons.collection;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.jenkon.commons.collection.decorator.ListDecorator;

/**
 * @author Jens Konopka
 * 
 * @param <E>
 *            the entry type of {@link List}
 */
public class ObservableList<E> extends ListDecorator<E> {

	/**
	 * 
	 */
	private static final long serialVersionUID = 7362484262865435775L;

	private final List<ListObserver<E>> observers = new ArrayList<ListObserver<E>>();

	/**
	 * @param list
	 *            the decorator and delegating {@link List}
	 */
	public ObservableList(final List<E> list) {
		super(list);
	}

	/**
	 * Add a {@link ListObserver} to {@link #observers}.
	 * 
	 * @param observer
	 *            {@link ListObserver}
	 */
	public void addObserver(final ListObserver<E> observer) {
		observers.add(observer);
	}

	/**
	 * Remove a {@link ListObserver} from {@link #observers}.
	 * 
	 * @param observer
	 *            {@link ListObserver}
	 */
	public void removeObserver(final ListObserver<E> observer) {
		observers.remove(observer);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jenkon.decorator.ListDecorator#add(java.lang.Object)
	 */
	@Override
	public boolean add(final E e) {
		final boolean result = super.add(e);
		for (final ListObserver<E> observer : observers) {
			observer.add(e);
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jenkon.decorator.ListDecorator#remove(int)
	 */
	@Override
	public E remove(final int index) {
		final E e = super.remove(index);
		for (final ListObserver<E> observer : observers) {
			observer.remove(index, e);
		}
		return e;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jenkon.decorator.ListDecorator#remove(java.lang.Object)
	 */
	@Override
	public boolean remove(final Object o) {
		final boolean result = super.remove(o);
		for (final ListObserver<E> observer : observers) {
			observer.remove(o, result);
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jenkon.decorator.ListDecorator#removeAll(java.util.Collection)
	 */
	@Override
	public boolean removeAll(final Collection<?> c) {
		final boolean result = super.removeAll(c);
		for (final ListObserver<E> observer : observers) {
			observer.removeAll(c, result);
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jenkon.decorator.ListDecorator#clear()
	 */
	@Override
	public void clear() {
		super.clear();
		for (final ListObserver<E> observer : observers) {
			observer.clear();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jenkon.decorator.ListDecorator#addAll(java.util.Collection)
	 */
	@Override
	public boolean addAll(final Collection<? extends E> c) {
		final boolean result = super.addAll(c);
		for (final ListObserver<E> observer : observers) {
			observer.addAll(c, result);
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jenkon.decorator.ListDecorator#addAll(int, java.util.Collection)
	 */
	@Override
	public boolean addAll(final int index, final Collection<? extends E> c) {
		final boolean result = super.addAll(index, c);
		for (final ListObserver<E> observer : observers) {
			observer.addAll(index, c, result);
		}
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jenkon.decorator.ListDecorator#add(int, java.lang.Object)
	 */
	@Override
	public void add(final int index, final E element) {
		super.add(index, element);
		for (final ListObserver<E> observer : observers) {
			observer.add(index, element);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jenkon.decorator.ListDecorator#set(int, java.lang.Object)
	 */
	@Override
	public E set(final int index, final E element) {
		final E previous = super.set(index, element);
		for (final ListObserver<E> observer : observers) {
			observer.set(index, element, previous);
		}
		return previous;
	}

	/**
	 * @author Jens Konopka
	 * 
	 * @param <E>
	 *            the type of entry
	 */
	public interface ListObserver<E> extends Serializable {

		/**
		 * @param index
		 *            the index of the entry to remove
		 * @param e
		 *            the entry to remove
		 */
		void remove(final int index, final E e);

		/**
		 * @param o
		 *            the object to remove
		 * @param result
		 *            is the object removed
		 */
		void remove(final Object o, final boolean result);

		/**
		 * @param c
		 *            the {@link Collection} to remove
		 * @param result
		 *            is removed
		 */
		void removeAll(final Collection<?> c, final boolean result);

		/**
		 * @param index
		 *            the position to add the new element
		 * @param element
		 *            the new element
		 * @param previous
		 *            the previously element at the position
		 */
		void set(final int index, final E element, final E previous);

		/**
		 * @param e
		 *            Entry
		 */
		void add(final E e);

		/**
		 * @param index
		 *            the position in {@link List} to add the element
		 * @param element
		 *            the element to add on the position
		 */
		void add(final int index, final E element);

		/**
		 * @param c
		 *            {@link Collection} to add
		 * @param result
		 *            is {@link Collection} added
		 */
		void addAll(final Collection<? extends E> c, final boolean result);

		/**
		 * @param index
		 *            the position to insert
		 * @param c
		 *            the {@link Collection} to add at the position
		 * @param result
		 *            is {@link Collection} added
		 */
		void addAll(final int index, final Collection<? extends E> c,
				final boolean result);

		/**
		 * 
		 */
		void clear();

	}

}
